package org.light.simpleauth;

import java.util.ArrayList;
import java.util.List;

import org.light.core.Writeable;
import org.light.domain.Domain;
import org.light.domain.Statement;
import org.light.domain.StatementList;
import org.light.domain.Util;
import org.light.utils.DomainUtil;
import org.light.utils.StringUtil;
import org.light.utils.WriteableUtil;

public class PasswordUtilGenerator extends Util{
	protected Domain userDomain;

	public PasswordUtilGenerator(String packageToken,Domain userDomain){
		super();
		this.setPackageToken(packageToken);
		this.setUserDomain(userDomain);
		super.fileName = "PasswordUtil.go";
	}

	@Override
	public String generateUtilString() throws Exception{
		if ("datadummy".equalsIgnoreCase(this.userDomain.getSchema())) {
			return generateDataDummyUtilStatements().getContent();
		} else {
			List<Writeable> sList = new ArrayList<Writeable>();
			sList.add(new Statement(1000L,0,"package utils"));
			sList.add(new Statement(2000L,0,""));
			
			sList.add(new Statement(2100L,0,"import ("));
			sList.add(new Statement(2200L,1,"\"database/sql\""));
			sList.add(new Statement(2400L,1,"\"math/rand\""));
			sList.add(new Statement(2500L,1,"\"fmt\""));
			sList.add(new Statement(2700L,0,")"));
			
			sList.add(new Statement(3000L,0,"func GenerateSalt(db *sql.DB) string {"));
			sList.add(new Statement(4000L,1,"salt := \"\""));
			sList.add(new Statement(5000L,1,"var saltletters = [16]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}"));
			sList.add(new Statement(6000L,0,""));
			sList.add(new Statement(7000L,1,"for !Uniquesalt(db,salt) {"));
			sList.add(new Statement(8000L,2,"salt = \"\""));
			sList.add(new Statement(9000L,2,"for i := 0; i < 32; i++ {"));
			sList.add(new Statement(10000L,3,"salt += string(saltletters[rand.Intn(16)])"));
			sList.add(new Statement(11000L,2,"}"));
			sList.add(new Statement(12000L,1,"}"));
			sList.add(new Statement(13000L,1,"return salt"));
			sList.add(new Statement(14000L,0,"}"));
			
			sList.add(new Statement(15000L,0,"func Uniquesalt(db *sql.DB,salt string) bool {"));
			sList.add(new Statement(16000L,1,"if salt != \"\" {"));
			if ("MySQL".equalsIgnoreCase(this.userDomain.getDbType())||"MariaDB".equalsIgnoreCase(this.userDomain.getDbType())) {
				sList.add(new Statement(18000L,2,"query := \"select count("+StringUtil.changeDomainFieldtoTableColum(this.userDomain.getDomainId().getLowerFirstFieldName())+") as countNum from  "+DomainUtil.getTableName(this.userDomain)+" where "+StringUtil.changeDomainFieldtoTableColum(this.userDomain.findFieldByFixedName("salt").getLowerFirstFieldName())+"=?\""));
			} else if ("PostgreSQL".equalsIgnoreCase(this.userDomain.getDbType())||"pgsql".equalsIgnoreCase(this.userDomain.getDbType())) {
				sList.add(new Statement(18000L,2,"query := \"select count("+StringUtil.changeDomainFieldtoTableColum(this.userDomain.getDomainId().getLowerFirstFieldName())+") as countNum from  "+DomainUtil.getTableName(this.userDomain)+" where "+StringUtil.changeDomainFieldtoTableColum(this.userDomain.findFieldByFixedName("salt").getLowerFirstFieldName())+"=$1\""));
			} else if ("Oracle".equalsIgnoreCase(this.userDomain.getDbType())) {
				sList.add(new Statement(18000L,2,"query := \"select count("+StringUtil.changeDomainFieldtoTableColum(this.userDomain.getDomainId().getLowerFirstFieldName())+") as countNum from  "+DomainUtil.getTableName(this.userDomain)+" where "+StringUtil.changeDomainFieldtoTableColum(this.userDomain.findFieldByFixedName("salt").getLowerFirstFieldName())+"=:"+this.userDomain.findFieldByFixedName("salt").getLowerFirstFieldName()+"\""));
			}
				
			sList.add(new Statement(19000L,2,"stmt, err := db.Prepare(query)"));
			sList.add(new Statement(20000L,2,"defer stmt.Close()"));
			sList.add(new Statement(21000L,2,"if err != nil {"));
			sList.add(new Statement(22000L,3,"panic(err)"));
			sList.add(new Statement(23000L,2,"}"));
			sList.add(new Statement(24000L,2,"row := stmt.QueryRow(salt)"));
			sList.add(new Statement(25000L,2,"if err != nil {"));
			sList.add(new Statement(26000L,3,"panic(err)"));
			sList.add(new Statement(27000L,2,"}"));
			sList.add(new Statement(28000L,2,"var count int32"));
			sList.add(new Statement(29000L,2,"err = row.Scan(&count)"));
			sList.add(new Statement(30000L,2,"if err != nil {"));
			sList.add(new Statement(31000L,3,"panic(err)"));
			sList.add(new Statement(32000L,2,"}"));
			sList.add(new Statement(33000L,2,"return count == 0"));
			sList.add(new Statement(34000L,1,"} else {"));
			sList.add(new Statement(35000L,2,"fmt.Println(\"The salt is empty!\")"));
			sList.add(new Statement(36000L,2,"return false"));
			sList.add(new Statement(37000L,1,"}"));
			sList.add(new Statement(38000L,0,""));
			sList.add(new Statement(39000L,0,"}"));
			return WriteableUtil.merge(sList).getContent();
		}
	}

	public Domain getUserDomain() {
		return userDomain;
	}

	public void setUserDomain(Domain userDomain) {
		this.userDomain = userDomain;
	}
	
	public StatementList generateDataDummyUtilStatements() throws Exception{
		List<Writeable> sList = new ArrayList<Writeable>();
		sList.add(new Statement(1000L,0,"package utils"));
		sList.add(new Statement(2000L,0,""));
		sList.add(new Statement(3000L,0,"import ("));
		sList.add(new Statement(4000L,1,"\""+DomainUtil.packagetokenToGoPackageFolder(this.userDomain.getProjectName(),this.userDomain.getPackageToken()+"."+this.userDomain.getDomainSuffix()+"\"")));
		sList.add(new Statement(5000L,1,"\"database/sql\""));
		sList.add(new Statement(6000L,1,"\"fmt\""));
		sList.add(new Statement(7000L,1,"\"math/rand\""));
		sList.add(new Statement(8000L,0,")"));
		sList.add(new Statement(9000L,0,""));
		sList.add(new Statement(10000L,0,"func GenerateSalt(db *sql.DB, "+this.userDomain.getLowerFirstDomainName()+"Db []"+this.userDomain.getDomainSuffix()+"."+this.userDomain.getCapFirstDomainNameWithSuffix()+") string {"));
		sList.add(new Statement(11000L,1,"salt := \"\""));
		sList.add(new Statement(12000L,1,"var saltletters = [16]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}"));
		sList.add(new Statement(13000L,0,""));
		sList.add(new Statement(14000L,1,"for !Uniquesalt(db, salt, "+this.userDomain.getLowerFirstDomainName()+"Db) {"));
		sList.add(new Statement(15000L,2,"salt = \"\""));
		sList.add(new Statement(16000L,2,"for i := 0; i < 32; i++ {"));
		sList.add(new Statement(17000L,3,"salt += string(saltletters[rand.Intn(16)])"));
		sList.add(new Statement(18000L,2,"}"));
		sList.add(new Statement(19000L,1,"}"));
		sList.add(new Statement(20000L,1,"return salt"));
		sList.add(new Statement(21000L,0,"}"));
		sList.add(new Statement(22000L,0,"func Uniquesalt(db *sql.DB, salt string, "+this.userDomain.getLowerFirstDomainName()+"Db []"+this.userDomain.getDomainSuffix()+"."+this.userDomain.getCapFirstDomainNameWithSuffix()+") bool {"));
		sList.add(new Statement(23000L,1,"if salt != \"\" {"));
		sList.add(new Statement(24000L,2,"count := 0"));
		sList.add(new Statement(25000L,2,"for _, "+this.userDomain.getLowerFirstDomainName()+"0 := range "+this.userDomain.getLowerFirstDomainName()+"Db {"));
		sList.add(new Statement(26000L,3,"if "+this.userDomain.getLowerFirstDomainName()+"0.Get"+this.userDomain.findFieldByFixedName("salt").getCapFirstFieldName()+"() == salt {"));
		sList.add(new Statement(27000L,4,"count++"));
		sList.add(new Statement(28000L,3,"}"));
		sList.add(new Statement(29000L,2,"}"));
		sList.add(new Statement(30000L,2,"return count == 0"));
		sList.add(new Statement(31000L,1,"} else {"));
		sList.add(new Statement(32000L,2,"fmt.Println(\"The salt is empty!\")"));
		sList.add(new Statement(33000L,2,"return false"));
		sList.add(new Statement(34000L,1,"}"));
		sList.add(new Statement(35000L,0,"}"));

		return WriteableUtil.merge(sList);
	}
}
